﻿//----------------------------------------------------------------------------------------------------
// The Turn Manager is responsible for processing pending actions in a turn step
//----------------------------------------------------------------------------------------------------
package HG.Managers
{
	import HG.Debug;
	
	import HG.GameService;
	import HG.Managers.GameRuleManager;
	
	import HG.Actions.IAction;
	
	import HG.Events.GameEvent;
	import HG.Events.TurnEvent;
	import HG.Events.PlayerEvent;
	
	import HG.GameDataTypes.Turn;
	import HG.GameDataTypes.Player;
	
	public class TurnManager extends IGameManager
	{
		var m_currentTurnID:Number;
		var m_turnMap:Array;
		
		var m_pendingRepeatedActions:Array;
		
		var m_tEvt:TurnEvent;
		
		var m_currentPlayerTurnIndex:Number;
		var m_currentPlayerTurn:Number;
		
		var m_gameRuleManager:GameRuleManager;
		var m_playerManager:PlayerManager;
		var m_actionManager:ActionManager;
		
		var m_turnInProgress:Boolean;

		//----------------------------------------------------------------------------------------------------
		public function TurnManager():void
		{
			m_pendingRepeatedActions = new Array();	
			m_currentPlayerTurn = 0;
			m_currentPlayerTurnIndex = 0;
			
			m_turnInProgress = false;
		}

		//----------------------------------------------------------------------------------------------------
		override public function Initialize()
		{
			m_gameRuleManager = GameService.GetInstance().GetGameRuleManager();
			m_playerManager = GameService.GetInstance().GetPlayerManager();
			m_actionManager = GameService.GetInstance().GetActionManager();
			
			m_gameRuleManager.addEventListener(GameEvent.BEGIN, OnGameStarted);
		}

		//----------------------------------------------------------------------------------------------------
		override public function Shutdown()
		{

		}

		//----------------------------------------------------------------------------------------------------
		override public function OnTick(DeltaTime:Number)
		{

		}
		
		//----------------------------------------------------------------------------------------------------
		// External functions
		//----------------------------------------------------------------------------------------------------
		private function OnGameStarted(evt:GameEvent)
		{
			m_currentTurnID = 0;
			m_turnMap = new Array();
			
			BeginTurn();
		}

		//----------------------------------------------------------------------------------------------------
		// Internal functions
		//----------------------------------------------------------------------------------------------------
		function RemoveTurn(turnID:Number)
		{
			Debug.ASSERT(turnID > 0 && turnID < m_turnMap.length, "Attempt to remove turn outside of bounds.");

			m_turnMap.splice(turnID, 1);
		}

		//----------------------------------------------------------------------------------------------------
		public function GetNextTurnID():Number
		{
			m_currentTurnID++;

			if (m_currentTurnID > m_turnMap.length)
			{
				var newTurn:Turn = new Turn(m_currentTurnID);
				m_turnMap[m_currentTurnID] = newTurn;
			}

			Debug.ASSERT(m_turnMap[m_currentTurnID], "Turn does not exist: " + m_currentTurnID);

			return m_currentTurnID;
		}
		
		//----------------------------------------------------------------------------------------------------
		// External calls
		//----------------------------------------------------------------------------------------------------
		public function PlayerInputComplete(ID:Number)
		{
			if (m_currentPlayerTurn != ID)
			{
				Debug.Trace("Not your turn: " + ID);
				return;
			}
			
			if (!m_turnInProgress)
				return;
			
			ExecuteTurn();
		}
		
		//----------------------------------------------------------------------------------------------------
		// Events
		//----------------------------------------------------------------------------------------------------
		private function RaiseTurnBeginEvent(ID:Number)
		{
			m_tEvt = new TurnEvent(TurnEvent.BEGIN);
			m_tEvt.m_turnID = ID;
			m_tEvt.m_inputPlayerID = m_currentPlayerTurn;
			dispatchEvent(m_tEvt);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function RaiseTurnEndEvent(ID:Number)
		{
			m_tEvt = new TurnEvent(TurnEvent.END);
			m_tEvt.m_turnID = ID;
			dispatchEvent(m_tEvt);
		}

		//----------------------------------------------------------------------------------------------------
		// Creates a new turn, or loads an exisitng one (if in sequence)
		//----------------------------------------------------------------------------------------------------
		public function BeginTurn()
		{
			GetNextTurnID();
			m_turnInProgress = true;
			
			// Do any repeated actions here.
			var index:Number = 0;
			var listLength:Number = m_pendingRepeatedActions.length;
			
			for (index = 0; index < listLength; ++index)
			{
				AddPendingAction(m_pendingRepeatedActions[index]);
			}
			
			m_pendingRepeatedActions = new Array();
			
			
			m_currentPlayerTurn = GetNextPlayer();
			
			RaiseTurnBeginEvent(m_currentTurnID);
		}
		
		//----------------------------------------------------------------------------------------------------
		// Used for any actions that take multiple turns to complete.
		//----------------------------------------------------------------------------------------------------
		public function AddPendingRepeatedAction(action:IAction)
		{
			m_pendingRepeatedActions.push(action);
		}

		//----------------------------------------------------------------------------------------------------
		// Add a pending action to the current turn
		//----------------------------------------------------------------------------------------------------
		public function AddPendingAction(action:IAction)
		{
			if (!m_turnInProgress)
				return;
			
			Debug.ASSERT(m_turnMap[m_currentTurnID], "current turn does not exist");
			Debug.ASSERT(action, "attempt to add bad action to current turn");
			
			// Add this action to the current turn
			m_turnMap[m_currentTurnID].AddAction(action);
		}


		//----------------------------------------------------------------------------------------------------
		public function ExecuteTurn()
		{
			m_turnInProgress = false;
			var actionsToProcess:Array = m_turnMap[m_currentTurnID].GetActions();
			
			m_actionManager.ExecuteActions(actionsToProcess);
		}
		
		//----------------------------------------------------------------------------------------------------;
		// Ends the current turn
		//----------------------------------------------------------------------------------------------------
		public function EndTurn()
		{
			// TODO: serialise turns past? replays?
			// Remove the current turn from the turn list
			RemoveTurn(m_currentTurnID);
			
			RaiseTurnEndEvent(m_currentTurnID);
			
			// Now go to the next turn.
			BeginTurn();
		}

		//----------------------------------------------------------------------------------------------------
		public function GetNextPlayer():Number
		{
			m_currentPlayerTurnIndex++;
			
			var playerIDs:Array = m_playerManager.GetPlayerIDs();
			
			if (m_currentPlayerTurnIndex >= playerIDs.length)
			{
				m_currentPlayerTurnIndex = 0;
			}
			
			var nextPlayerID:Number = playerIDs[m_currentPlayerTurnIndex];
			
			if (m_playerManager.GetPlayer(nextPlayerID).GetType() == PlayerManager.PLAYER_ENVIRONMENT)
				nextPlayerID = GetNextPlayer();
			
			return nextPlayerID;
		}
		
		//----------------------------------------------------------------------------------------------------
	}
}